package nl.han.ica.ap.searchengine.shared.database;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import nl.han.ica.ap.searchengine.shared.sdo.Webpage;

/**
  * This class allows the application to easily communicate with a database. The database
  * and it's location/authentication details are stored in this class, allowing for easy 
  * use.
  * 
  * <p><strong>Example usage:</strong>
  * <pre>
  * {@code SearchEngineDatabase sed = new SearchEngineDatabase();
  * List<Webpage> pages = sed.getAll();}
  * </pre>
  * 
  * @author W. ter Berg
  */
public class SearchEngineDatabase {

	private static final String CONNECTION_STRING = "jdbc:mysql://localhost:3306/SearchEngine";
	private static final String CONNECTION_USERNAME = "searchengine_user";
	private static final String CONNECTION_PASSWORD = "supersecretpassword";

	private static final String PREPAREDSTATEMENT_BATCH_INSERT = 
			"INSERT INTO `Webpage`" +
			"       (`url`, `content`, `pagerank`) " +
			"       VALUES(?, ?, ?)";
	private static final String PREPAREDSTATEMENT_GETALL = 
			"SELECT `url`, `content`, `pagerank` " +
			"FROM `Webpage`";

	private Connection con;

	/**
	  * Creates a new SearchEngineDatabase object and opens the connection to the database. Use
	  * the {@link #close()} method to close the connection.
	  * @throws DatabaseConnectionException Thrown when an error occurred while connecting to the 
	  * database.
	  */
	public SearchEngineDatabase() throws DatabaseConnectionException {
		try {
			this.con = DriverManager.getConnection(CONNECTION_STRING, CONNECTION_USERNAME, CONNECTION_PASSWORD);
		} catch (SQLException e) {
			throw new DatabaseConnectionException();
		}
	}
	
	/**
	  * Closes the current connection to the database rendering this object useless. 
	  */
	public void close() {
		this.con = null;
	}

	/**
	  * Inserts every Webpage given as an argument to this method in the database. All
	  * properties of the Webpage objects need to have a value.
	  * 
	  * @param batch A List of Webpages that are to be inserted into the database.
	  * @throws DatabaseQueryException Thrown when any error occurs while communicating
	  * with the database.
	  */
	public void batchInsert(final List<Webpage> batch) throws DatabaseQueryException {
		if (this.con == null)
			return;
		
		if (batch.size() == 0)
			return;

		PreparedStatement query;
		try {
			query = this.con.prepareStatement(PREPAREDSTATEMENT_BATCH_INSERT);

			for (Webpage page : batch) {
				query.setString(1, page.getUrl());
				query.setString(2, page.getContents());
				query.setInt(3, page.getRank());
				query.addBatch();
			}

			query.executeBatch();
			query.close();
		} catch (SQLException e) {
			throw new DatabaseQueryException();
		}
	}

	/**
	  * Retrieves all webpages stored in the database.
	  * 
	  * @return Returns a List of all Webpages stored in the database.
	  * @throws DatabaseQueryException Thrown when any error occurs while
	  * communicating with the database.
	  */
	public List<Webpage> getAll() throws DatabaseQueryException {
		if (this.con == null)
			return null;

		PreparedStatement query;
		List<Webpage> results = new ArrayList<Webpage>();
		try {
			query = this.con.prepareStatement(PREPAREDSTATEMENT_GETALL);
			query.execute();

			ResultSet result = query.executeQuery();

			while (result.next()) {
				results.add(
					new Webpage(
						result.getString("url"), 
						result.getString("content"), 
						result.getInt("pagerank")
					)
				);
			}
		} catch (SQLException e) {
			throw new DatabaseQueryException();
		}

		return results;
	}

	/**
	  * Search for specific Webpages stored in the database using the databases
	  * native search functionality.
	  * 
	  * @param query What to search for.
	  * @return Returns a List of all Webpages that match the search query.
	  */
	public List<Webpage> searchFor(final String query) {
		return null;
	}

}
